package org.example.hw.service;

import java.util.List;

import javax.annotation.Resource;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.example.hw.exception.CustomLinkDoesNotExistException;
import org.example.hw.exception.CustomLinkExistsException;
import org.example.hw.exception.MyException;
import org.example.hw.exception.UserDoesNotExistException;
import org.example.hw.model.Link;
import org.example.hw.model.User;
import org.example.hw.repository.LinkRepository;
import org.example.hw.repository.UserRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional(readOnly = true)
public class LinkServiceImpl implements LinkService {

	private static final Logger LOGGER = LogManager.getLogger(LinkServiceImpl.class);

	@Resource
	private LinkRepository linkRepository;

	@Resource
	private UserRepository userRepository;

	@Override
	public Link save(Link link) throws MyException {

		User user = link.getCreatedBy();

		if (user == null) { // anonymous

			LOGGER.info("Anonymous created link...");

			// TODO: ispitati kako se ponaša kada anoniman korisnik doda custom link. ako radi, ne treba glavni if-else
			Link existing = linkRepository.findLinkByCreatedByAndCustomUrl(null, link.getCustomUrl());

			if (existing != null) {
				LOGGER.info("Custom url not unique");
				throw new CustomLinkExistsException("Custom url '" + link.getCustomUrl() + "' not unique.");
			}

		} else {

			LOGGER.info("User that created link: " + user);

			Link existing = linkRepository.findLinkByCreatedByAndCustomUrl(link.getCreatedBy(), link.getCustomUrl());

			if (existing != null) {
				LOGGER.info("Custom url not unique for user");
				throw new CustomLinkExistsException("Custom url '" + link.getCustomUrl() + "' not unique.");
			}

		}

		LOGGER.info("Saving link: " + link);

		return linkRepository.save(link);
	}

	@Transactional(readOnly = false)
	@Override
	public Link update(Link link) {

		LOGGER.info("Updating link: " + link);

		return linkRepository.save(link);
	}

	@Transactional(readOnly = false)
	@Override
	public void delete(Link id) {

		LOGGER.info("Deleting link with id: " + id);

		linkRepository.delete(id);
	}

	@Override
	public List<Link> findAll() {

		LOGGER.info("Fetching all links...");

		return linkRepository.findAll();
	}

	@Override
	public Link findById(Long id) {

		LOGGER.info("Finding link with id: " + id);

		return linkRepository.findOne(id);
	}

	@Override
	public Link findLinkByUsernameAndCustomUrl(String username, String customUrl) throws UserDoesNotExistException {

		LOGGER.info("Finding link from user with username: '" + username + "' and by custom url: '" + customUrl
				+ "'");

		User user = userRepository.findUserByUsername(username);

		if (user == null) {
			throw new UserDoesNotExistException("User with username '" + username + "' does not exist.");
		}

		LOGGER.info("User found: " + user);

		return linkRepository.findLinkByCreatedByAndCustomUrl(user, customUrl);
	}

	@Override
	public Link findLinkByCreatedByAndCustomUrl(String username, String customUrl, User sessionUser)
			throws MyException {

		User createdBy = userRepository.findUserByUsername(username);

		if (createdBy == null) {
			LOGGER.info("No user found with username: " + username);

			throw new UserDoesNotExistException("User with username '" + username + "' does not exist.");
		}

		LOGGER.info("Finding link by user '" + createdBy + "' and by custom url: '" + customUrl + "'");

		Link foundLink = linkRepository.findLinkByCreatedByAndCustomUrl(createdBy, customUrl);

		if (foundLink == null) {
			throw new CustomLinkDoesNotExistException("Custom link does not exist with custom url '" + customUrl
					+ "' and which is created by user: " + createdBy);
		}

		if (foundLink != null && !sessionUser.equals(createdBy)) { // if link creator isn't viewing his own link
			linkRepository.save(foundLink); // persist updated link view count
		}

		return foundLink;
	}

	@Override
	public Link findAnonmyousUserLink(String customUrl) throws CustomLinkDoesNotExistException {

		Link link = linkRepository.findLinkByCreatedByAndCustomUrl(null, customUrl);

		if (link == null) {
			throw new CustomLinkDoesNotExistException("Link with custom url '" + customUrl + "' does not exist.");
		}

		return link;
	}
}
